package com.ojoin.trade.common.web.ldap;

import java.net.URI;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.shiro.codec.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ojoin.trade.common.utils.security.AESTools;
import com.ojoin.trade.common.web.dao.RoleDao;
import com.ojoin.trade.common.web.domain.Role;

@Service
public class LdapSettingsImpl   implements LdapSettings {

	protected final Map<String, Object> fields=new HashMap<String, Object>();

    private static final Logger LOG = LoggerFactory.getLogger(LdapSettingsImpl.class);

    public static final String ENABLED = "enabled";
    public static final String SYSTEM_USERNAME = "system_username";
    public static final String SYSTEM_PASSWORD = "system_password";
    public static final String SYSTEM_PASSWORD_SALT = "system_password_salt";
    public static final String LDAP_URI = "ldap_uri";
    public static final String SEARCH_PATTERN = "principal_search_pattern";
    public static final String SEARCH_BASE = "search_base";
    public static final String DISPLAY_NAME_ATTRIBUTE = "username_attribute";
    public static final String USE_START_TLS = "use_start_tls";
    public static final String ACTIVE_DIRECTORY = "active_directory";
    public static final String DEFAULT_GROUP = "default_group";
    public static final String TRUST_ALL_CERTS = "trust_all_certificates";
    public static final String GROUP_MAPPING = "group_role_mapping";
    public static final String GROUP_MAPPING_LIST = "group_role_mapping_list";
    public static final String GROUP_SEARCH_BASE = "group_search_base";
    public static final String GROUP_ID_ATTRIBUTE = "group_id_attribute";
    public static final String GROUP_SEARCH_PATTERN = "group_search_pattern";
    public static final String ADDITIONAL_DEFAULT_GROUPS = "additional_default_groups";

    public static final String LDAP_GROUP_MAPPING_NAMEKEY = "group";
    public static final String LDAP_GROUP_MAPPING_ROLEKEY = "role_id";

    
    @Autowired
	private RoleDao roleDao;


    @Override
    public String getSystemUserName() {
        return Strings.nullToEmpty((String) fields.get(SYSTEM_USERNAME));
    }

    @Override
    public void setSystemUsername(String systemUsername) {
        fields.put(SYSTEM_USERNAME, systemUsername);
    }

    @Override
    public String getSystemPassword() {
        final Object o = fields.get(SYSTEM_PASSWORD);
        if (o == null) return "";
        if (getSystemPasswordSalt().isEmpty()) {
            return o.toString();
        }
        String encryptedPw = o.toString();
        return AESTools.decrypt(
                encryptedPw,
                "1234567890987654",
                getSystemPasswordSalt());
    }

    @Override
    public void setSystemPassword(String systemPassword) {
        // set new salt value, if we didn't have any.
        if (getSystemPasswordSalt().isEmpty()) {
            LOG.debug("Generating new salt for LDAP system password.");
            final SecureRandom random = new SecureRandom();
            byte[] saltBytes = new byte[8];
            random.nextBytes(saltBytes);
            setSystemPasswordSalt(Hex.encodeToString(saltBytes));
        }
        final String encrypted = AESTools.encrypt(
                systemPassword,
                "1234567890987654",
                getSystemPasswordSalt());
        fields.put(SYSTEM_PASSWORD, encrypted);
    }

    @Override
    public String getSystemPasswordSalt() {
        return Strings.nullToEmpty((String) fields.get(SYSTEM_PASSWORD_SALT));
    }

    @Override
    public void setSystemPasswordSalt(String salt) {
        fields.put(SYSTEM_PASSWORD_SALT, salt);
    }

    @Override
    public URI getUri() {
        final Object o = fields.get(LDAP_URI);
        return o != null ? URI.create(o.toString()) : null;
    }

    @Override
    public void setUri(URI ldapUri) {
        fields.put(LDAP_URI, ldapUri.toString());
    }

    @Override
    public String getSearchBase() {
        return Strings.nullToEmpty((String) fields.get(SEARCH_BASE));
    }

    @Override
    public void setSearchBase(String searchBase) {
        fields.put(SEARCH_BASE, searchBase);
    }

    @Override
    public String getSearchPattern() {
        return Strings.nullToEmpty((String) fields.get(SEARCH_PATTERN));
    }

    @Override
    public void setSearchPattern(String searchPattern) {
        fields.put(SEARCH_PATTERN, searchPattern);
    }

    @Override
    public String getDisplayNameAttribute() {
        return Strings.nullToEmpty((String) fields.get(DISPLAY_NAME_ATTRIBUTE));
    }

    @Override
    public void setDisplayNameAttribute(String displayNameAttribute) {
        fields.put(DISPLAY_NAME_ATTRIBUTE, displayNameAttribute);
    }

    @Override
    public boolean isEnabled() {
        final Object o = fields.get(ENABLED);
        return o != null ? Boolean.valueOf(o.toString()) : false;
    }

    @Override
    public void setEnabled(boolean enabled) {
        fields.put(ENABLED, enabled);
    }

    @Override
    public void setUseStartTls(boolean useStartTls) {
        fields.put(USE_START_TLS, useStartTls);
    }

    @Override
    public boolean isUseStartTls() {
        final Object o = fields.get(USE_START_TLS);
        return o != null ? Boolean.valueOf(o.toString()) : false;
    }

    @Override
    public void setActiveDirectory(boolean activeDirectory) {
        fields.put(ACTIVE_DIRECTORY, activeDirectory);
    }

    @Override
    public boolean isActiveDirectory() {
        final Object o = fields.get(ACTIVE_DIRECTORY);
        return o != null ? Boolean.valueOf(o.toString()) : false;
    }

    @Override
    public String getDefaultGroup() {
            return "14";
    }

    @Override
    public String getDefaultGroupId() {
        return "14";
    }

    @Override
    public void setDefaultGroup(String defaultGroup) {
    	Role roleP=new Role();
    	roleP.setEnname(defaultGroup);
    	
    	Role groupId =null;
        try {
            groupId = roleDao.getByEnname(roleP);
        } catch (Exception e) {
            LOG.error("Unable to load role mapping");
        }
        fields.put(DEFAULT_GROUP, groupId);
    }

    @Override
    public boolean isTrustAllCertificates() {
        return true;
    }

    @Override
    public void setTrustAllCertificates(boolean trustAllCertificates) {
    }

    @SuppressWarnings("unchecked")
    @Override
    public Map<String, String> getGroupMapping() {
    	final Map groupMapping = (Map) fields.get(GROUP_MAPPING);
    	if(null!=groupMapping){
    		return groupMapping;
    	}
         return Collections.emptyMap();
    }
    
    private static class RoleToNameFunction implements Function<Role, String> {
        private final boolean lowerCase;

        public RoleToNameFunction(boolean lowerCase) {
            this.lowerCase = lowerCase;
        }

        @Override
        public String apply(Role input) {
            if (input != null) {
                final String name = input.getEnname();
                return lowerCase ? name.toLowerCase(Locale.ENGLISH) : name;
            }
            else return null;
        }
    }

    @Override
    public void setGroupMapping(Map<String, String> mapping) {
        if (mapping == null) {
            fields.put(GROUP_MAPPING,Maps.newHashMap());
        } else {
        	fields.put(GROUP_MAPPING,mapping);
        }
    }

    @Override
    public String getGroupSearchBase() {
        return Strings.nullToEmpty((String) fields.get(GROUP_SEARCH_BASE));
    }

    @Override
    public void setGroupSearchBase(String groupSearchBase) {
        fields.put(GROUP_SEARCH_BASE, groupSearchBase);
    }

    @Override
    public String getGroupIdAttribute() {
        return Strings.nullToEmpty((String) fields.get(GROUP_ID_ATTRIBUTE));
    }

    @Override
    public void setGroupIdAttribute(String groupIdAttribute) {
        fields.put(GROUP_ID_ATTRIBUTE, groupIdAttribute);
    }

    @Override
    public String getGroupSearchPattern() {
        return Strings.nullToEmpty((String) fields.get(GROUP_SEARCH_PATTERN));
    }

    @Override
    public void setGroupSearchPattern(String groupSearchPattern) {
        fields.put(GROUP_SEARCH_PATTERN, groupSearchPattern);
    }

    @Override
    public Set<String> getAdditionalDefaultGroups() {
        final Set<String> additionalGroups = getAdditionalDefaultGroupIds();
            return Collections.emptySet();
    }

    @Override
    public Set<String> getAdditionalDefaultGroupIds() {
        @SuppressWarnings("unchecked")
        final Set<String> additionalGroups = (Set<String>) fields.get(ADDITIONAL_DEFAULT_GROUPS);
        return additionalGroups == null ? Collections.<String>emptySet() : additionalGroups;
    }

    @Override
    public void setAdditionalDefaultGroups(Set<String> groupNames) {
        if (groupNames == null) return;
		fields.put(ADDITIONAL_DEFAULT_GROUPS, groupNames);

    }
}
